package org.hibernate.engine.jdbc.dialect.internal;

import org.hibernate.dialect.Database;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.MySQL55Dialect;
import org.hibernate.dialect.MySQL57Dialect;
import org.hibernate.dialect.MySQL5Dialect;
import org.hibernate.dialect.MySQL8Dialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.Oracle10gDialect;
import org.hibernate.dialect.Oracle12cDialect;
import org.hibernate.dialect.Oracle8iDialect;
import org.hibernate.dialect.Oracle9iDialect;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolver;
import org.hibernate.mapping.Table;
import org.hibernate.tool.schema.internal.StandardTableExporter;
import org.hibernate.tool.schema.internal.StandardTableExtendExporter;
import org.hibernate.tool.schema.spi.Exporter;

/**
 * 数据库方言解析器实现类
 */
@SuppressWarnings("serial")
public class StandardDialectResolverExtend implements DialectResolver {

	@Override
	public Dialect resolveDialect(final DialectResolutionInfo info) {
		final Dialect resolved = this.resolve(info);
		if (resolved != null) { return resolved; }
		for (final Database database : Database.values()) {
			final Dialect dialect = database.resolveDialect(info);
			if (dialect != null) {
				return dialect;
			}
		}
		return null;
	}

	// 以下代码与Database中对应的解析一致，只是为对应的Dialect的getTableExporter方法构建一个StandardTableExporter的扩展实现。
	// 很遗憾，即使这确定是相同的代码，但是也不得不这样做。
	// 因目前kinyx-framework-db也只做了MySQL和Oracle的实现，所以兼容性上也只能验证MySQL和Oracle。
	// 与framework涉及思路一致，如需扩展其它数据库，参考已实现的数据库方言，做对应的实现并提供starter配置你的实现即可。
	public Dialect resolve(final DialectResolutionInfo info) {
		final String databaseName = info.getDatabaseName();

		switch (databaseName) {
			case "MySQL": {
				final int majorVersion = info.getDatabaseMajorVersion();
				final int minorVersion = info.getDatabaseMinorVersion();

				if (majorVersion < 5) {
					return new MySQLDialect() {
						private StandardTableExporter tableExporter = new StandardTableExtendExporter(this);
						@Override
						public Exporter<Table> getTableExporter() { return this.tableExporter; }
					};
				} else if (majorVersion == 5) {
					if (minorVersion < 5) {
						return new MySQL5Dialect() {
							private StandardTableExporter tableExporter = new StandardTableExtendExporter(this);
							@Override
							public Exporter<Table> getTableExporter() { return this.tableExporter; }
						};
					} else if (minorVersion < 7) {
						return new MySQL55Dialect() {
							private StandardTableExporter tableExporter = new StandardTableExtendExporter(this);
							@Override
							public Exporter<Table> getTableExporter() { return this.tableExporter; }
						};
					} else {
						return new MySQL57Dialect() {
							private StandardTableExporter tableExporter = new StandardTableExtendExporter(this);
							@Override
							public Exporter<Table> getTableExporter() { return this.tableExporter; }
						};
					}
				} else if (majorVersion < 8) {
					// There is no MySQL 6 or 7.
					// Adding this just in case.
					return new MySQL57Dialect() {
						private StandardTableExporter tableExporter = new StandardTableExtendExporter(this);
						@Override
						public Exporter<Table> getTableExporter() { return this.tableExporter; }
					};
				} else if (majorVersion == 8) {
					return new MySQL8Dialect() {
						private StandardTableExporter tableExporter = new StandardTableExtendExporter(this);
						@Override
						public Exporter<Table> getTableExporter() { return this.tableExporter; }
					};
				}

				return new MySQL8Dialect();
			}
			case "Oracle": {
				final int majorVersion = info.getDatabaseMajorVersion();

				switch (majorVersion) {
					case 12:
						return new Oracle12cDialect() {
							private StandardTableExporter tableExporter = new StandardTableExtendExporter(this);
							@Override
							public Exporter<Table> getTableExporter() { return this.tableExporter; }
						};
					case 11:
						// fall through
					case 10:
						return new Oracle10gDialect() {
							private StandardTableExporter tableExporter = new StandardTableExtendExporter(this);
							@Override
							public Exporter<Table> getTableExporter() { return this.tableExporter; }
						};
					case 9:
						return new Oracle9iDialect() {
							private StandardTableExporter tableExporter = new StandardTableExtendExporter(this);
							@Override
							public Exporter<Table> getTableExporter() { return this.tableExporter; }
						};
					case 8:
						return new Oracle8iDialect() {
							private StandardTableExporter tableExporter = new StandardTableExtendExporter(this);
							@Override
							public Exporter<Table> getTableExporter() { return this.tableExporter; }
						};
					default :
						return new Oracle12cDialect() {
							private StandardTableExporter tableExporter = new StandardTableExtendExporter(this);
							@Override
							public Exporter<Table> getTableExporter() { return this.tableExporter; }
						};

				}
			}
			default :
				break;
		}

		return null;
	}

}
